﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Configuration;
using System.ServiceModel.Description;
using System.ServiceModel.Web;
using System.Text;
using System.Xml;

namespace WebHost
{


    public class HostManager
    {
        public bool _IsRuning;
        public bool IsRuning { get { return _IsRuning; } }
        private string[] _ServiceAssembleNames;
        private string ip;
        private int port;

        private List<WebServiceHost> hosts;

        public static string CurSystemPath { get { return System.AppDomain.CurrentDomain.BaseDirectory; } }

        public static string GetRootFilePath(string rootFilePath)
        {
            return Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)
             , rootFilePath);
        }

        //protected HostManager() { }
        public HostManager()
        {

        }

        public void Start(out string errMsg)
        {
            errMsg = "";
            LoadConfig(out errMsg);
            if (!string.IsNullOrWhiteSpace(errMsg))
                return;

            _ServiceAssembleNames = LoadServices(out errMsg);
            if (!string.IsNullOrWhiteSpace(errMsg))
                return;

            StartRESTHost(out errMsg);
            if (!string.IsNullOrWhiteSpace(errMsg))
                return;

            _IsRuning = true;
        }
        public void Stop()
        {
            StopRESTHost();

            _IsRuning = false;
        }

        public void LoadConfig(out string errMSg)
        {
            errMSg = "";

            XmlDocument doc = new XmlDocument();
             string path = Path.Combine(Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)
             , @".\config.xml");
            try
            {
                doc.Load(path);

                XmlNode node = doc.SelectSingleNode("service");


                string host = node.SelectSingleNode("host").InnerText;
                string port = node.SelectSingleNode("port").InnerText;

                this.ip = host;
                this.port = Int32.Parse(port);

            }
            catch
            {
                this.ip = "127.0.0.1";
                this.port = 8123;
            }




        }
        public string[] LoadServices(out string errMsg)
        {
            errMsg = "";
            try
            {
                List<string> result = new List<string>();
                //string str = ConfigurationManager.
                var node = ConfigurationManager.GetSection("system.serviceModel/services");
                if (node == null)
                    errMsg = "未发现WCF配置节点";
                ServicesSection servicesSection = node as ServicesSection;
                for (int i = 0; i < servicesSection.Services.Count; i++)
                {
                    string serverTypeName = servicesSection.Services[i].Name;
                    if (string.IsNullOrWhiteSpace(serverTypeName))
                    {
                        errMsg = "WCF加载服务列表服务类型名称错误";
                        return new string[0];
                    }         
                    result.Add(serverTypeName);
                }
                return result.ToArray();
            }
            catch(Exception e) {
                errMsg = "WCF读取服务列表失败" + e.Message+e.StackTrace;
                return new string[0];
            }
        }
        public string GetUrl(string assembleName)
        {
            return string.Join("/", "http://"+this.ip+":" + port,GetServerType(assembleName));
        }
        public string GetServerType(string assembleName)
        {
            return assembleName.Split('.')[0];
        }
        public string GetServerDllPath(string assembleName)
        {
            string test = Path.GetFileNameWithoutExtension(GetRootFilePath(assembleName.Split('.')[0] + ".dll"));
            return Path.GetFileNameWithoutExtension(GetRootFilePath(assembleName.Split('.')[0] + ".dll")) ;
        }

        public void StartRESTHost(out string errMsg)
        {
            errMsg = "";
            if (hosts == null)
                hosts = new List<WebServiceHost>();
            else
            {
                foreach (var host in hosts)
                {
                    host.Close();
                }
                hosts.Clear();
            }

            try
            {
                foreach (string serviceType in _ServiceAssembleNames)
                {
                    hosts.Add(StartRESTHost(serviceType));
                }
            }
            catch(Exception e)
            {
                errMsg = "WCF服务启动失败" + e.Message + e.StackTrace;
            }
        }
        public void StopRESTHost()
        {
            try
            {
                if (hosts != null)
                {
                    foreach (var host in hosts)
                    {
                        host.Close();
                    }
                    hosts.Clear();
                }
                hosts = null;
            }
            catch { }
        }

        public  WebServiceHost StartRESTHostForSelfConfig(string assembleName, string serviceType)
        {
            Type serverType = Assembly.Load(assembleName).GetType(assembleName);
            Uri baseAddress = new Uri(GetUrl(serviceType));
            var host = new WebServiceHost(serverType, baseAddress);
            #region ServiceBehavior
            {
                var serviceBehavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
                if (null == serviceBehavior)
                {
                    serviceBehavior = new ServiceBehaviorAttribute();
                    host.Description.Behaviors.Add(serviceBehavior);
                }
                serviceBehavior.ConcurrencyMode = ConcurrencyMode.Multiple;
                serviceBehavior.MaxItemsInObjectGraph = 65536000;
                serviceBehavior.InstanceContextMode = InstanceContextMode.PerCall;
            }
            #endregion

            #region AspNetCompatibilityRequirements
            {
                var aspNetCompatibilityRequirements = host.Description.Behaviors.Find<AspNetCompatibilityRequirementsAttribute>();
                if (null == aspNetCompatibilityRequirements)
                {
                    aspNetCompatibilityRequirements = new AspNetCompatibilityRequirementsAttribute();
                    host.Description.Behaviors.Add(aspNetCompatibilityRequirements);
                }
                aspNetCompatibilityRequirements.RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed;
            }
            #endregion

            #region ServiceDebugBehavior
            {
                var serviceDebugBehavior = host.Description.Behaviors.Find<ServiceDebugBehavior>();
                if (null == serviceDebugBehavior)
                {
                    serviceDebugBehavior = new ServiceDebugBehavior();
                    host.Description.Behaviors.Add(serviceDebugBehavior);
                }
                serviceDebugBehavior.IncludeExceptionDetailInFaults = true;
                serviceDebugBehavior.HttpHelpPageEnabled = true;
            }
            #endregion

            #region MyServiceBehaviorAttribute
            {
                var myServiceBehavior = host.Description.Behaviors.Find<MyServiceBehaviorAttribute>();
                if (null == myServiceBehavior)
                {
                    myServiceBehavior = new MyServiceBehaviorAttribute(serviceType);
                    host.Description.Behaviors.Add(myServiceBehavior);
                }
            }
            #endregion

            host.Open();

            return host;
        }
        public WebServiceHost StartRESTHost(string assembleName)
        {
            var test = Assembly.Load(GetServerDllPath(assembleName));
            Type serverType = Assembly.Load(GetServerDllPath(assembleName)).GetType(assembleName);
            Uri baseAddress = new Uri(GetUrl(assembleName));
             var host = new WebServiceHost(serverType, baseAddress);
            //var host = new WebServiceHost(typeof(RESTServer.REST), new Uri("http://localhost:3000/RESTServer/"));
            host.Open();
            return host;
        }


    }

}
